package cn.net.xyan.yypt.service

import cn.linkingcloud.openapi.LopClient
import cn.net.xyan.blossom.core.service.ConfigService
import cn.net.xyan.blossom.kotlin.*
import cn.net.xyan.yypt.dto.*
import com.fasterxml.jackson.databind.type.TypeFactory
import org.springframework.beans.factory.annotation.Autowired
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import javax.annotation.PostConstruct

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class MethodBind(val value: String)

interface LinkingCloudOpenApi{
    @MethodBind("lc.trade.qrcode.pay")
    fun createQRCodeOrder(req:CreateQRCodeOrderReq):LinkingCloudResponse<QRCodeRsp>

    @MethodBind("lc.trade.polymerization.pay")
    fun createPolymerizationQRCodeOrder(req:CreatePolymerizationQRCodeReq):LinkingCloudResponse<QRCodeRsp>

    @MethodBind("lc.trade.barcode.pay")
    fun createBarCodeOrder(req:CreateBarCodeOrderReq):LinkingCloudResponse<BarCodeRsp>

    @MethodBind("lc.trade.query")
    fun queryOrder(req:QueryOrderReq):LinkingCloudResponse<QueryOrderRsp>

    @MethodBind("lc.trade.fastpay.refund.query")
    fun queryRefund(req:QueryRefundReq):LinkingCloudResponse<QueryRefundRsp>

    @MethodBind("lc.trade.refund")
    fun refundOrder(req:RefundOrderReq):LinkingCloudResponse<RefundOrderRsp>
}

@AllOpen
class LinkingCloudOpenApiInvocationHandler: InvocationHandler {

    @Autowired
    lateinit var configService:ConfigService

    companion object {
        const val KeyOpenApiURL = "KeyOpenApiURL"
        const val KeyLCAppID = "KeyLCAppID"

        const val KeyLCCharset = "KeyLCCharset"
        const val KeyLCSignType = "KeyLCSignType"

        const val KeyLCAppPrivateKey= "KeyLCAppPrivateKey"
        const val KeyLCPublicKey = "KeyLCPublicKey"
    }

    @PostConstruct
    fun setup(){
        configService.setupVariable(KeyOpenApiURL,"http://openapi.linkingcloud.cn:8816/gateway","联空URL")
        configService.setupVariable(KeyLCAppID,"LCOP20171228012536079","联空AppID")
        configService.setupVariable(KeyLCCharset,"utf-8","联空字符编码")
        configService.setupVariable(KeyLCSignType,"rsa","联空签名算法")

        configService.setupVariable(KeyLCAppPrivateKey,
                "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALvIWviWfj31BZFJFxDzh2RmRUmJ5Rmc75okSkxdAyxOEXoQIOUXu5rrYXtJrp0wAxzLgzLwmDOfhgO/h2d5XrafUll6P8agL4pRML41J5xtTUCrISQph8/A4CiT0OfVsEmrVSU0Regn/PuUEdYmNboZLimOK/baP6/GJV+fX16hAgMBAAECgYB9afCn+grSYmSXhdMr9RnFyjAYT0p9crzrm7UrjythWbp+ZWsy1kjrzKzMZIeEX96USq+TQ/DC+ZXNxwst5neEJ5dODM679qjia/ziu6t6DQbHZJ6tgM1L2Ome0Runva4hLi8AA3UbziibzCfV50I9k+y4aqafKGzqf0qfmJ+MiQJBAOK79F4R/lkrZYDW4fePy9f8cGOYJcaRd1Vgwvb1c8YxNvMH+FWE+TrwvudLJfA6+kwEPRN0FgU5mGCDSPRpzJsCQQDUBVAWyB1hXZ+Y96TQhjMwuVQRLSfkcvSFnw1N0HziZDvnr+Cxekvd8aMbA/6f401yEtG1Gy31mdZVkOBWWC9zAkAcp/qzpPyLkpOKnB4FJvRxgONHgyRLG3mEne0mP1F5nCDAyKIXVO4XB/Ro0TOjUCDwWJzLh6F82ZGrqQwgb/q/AkEAlFf7R1VQqTU2W3K50GR1IJwq47Gyfbaou20jg9Rh7IyxFVQLZGHq/yj4NAjBeOEy6KOeMpcHuxWdz1SEgiVFXQJAHw+2yOrJRD4+zfido4iJwVu0YS+rJ3bROwvpO3HNArafzfia9h+n9jn7Fa2NinMwI+RKVZQOzTULecD9Reml5Q==",
                "联空应用私钥")
        configService.setupVariable(KeyLCPublicKey,
                "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDGncH9TmDGpqBy6MhH5j4eyR+jL8R5FF2Fzp7AR3dmlO/G3KRvqOexLm8xfyydaV0oF5e+t4j+b4sIksg72VkX3+aFLF0rIPoUx80sOCYsbs4ng3ohWKc4x4xixp7TIbSe5x+eVlw9yqGULIrmmISlv0emFyJSuXYoXDzjPeKn+wIDAQAB",
                "联空平台公钥")
    }

    fun client(): LopClient {
        val openApiURL = configService.queryValue(KeyOpenApiURL)
        val appID = configService.queryValue(KeyLCAppID)
        val charset = configService.queryValue(KeyLCCharset)
        val signType = configService.queryValue(KeyLCSignType)
        val privateKey = configService.queryValue(KeyLCAppPrivateKey)
        val publicKey = configService.queryValue(KeyLCPublicKey)

        return LopClient(openApiURL, appID, privateKey, charset, publicKey, signType)
    }

    override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any? {
        if (method?.isAnnotationPresent(MethodBind::class.java)?:throw StatusAndMessageError("method is null")) {
            val methodName = method?.getDeclaredAnnotation(MethodBind::class.java).value

            val jsonBody = if(args?.size == 1){
                args?.first()?.json
            }else{
                args?.json
            }
            logger.info("call $methodName : $jsonBody")
            val rsp = client().InvokeMethod(methodName,jsonBody)

            logger.info(rsp)

            return if (method.returnType != Unit::class.java) {

                val returnType = TypeFactory.defaultInstance().constructType(method.genericReturnType)

                return rsp.json2obj(returnType)

            } else {
                Unit
            }
        }else{
            logger.info("${method.name}")
            return if(method.name == "hashCode"){
                this.hashCode()
            }/*else if(method.name == "hashCode"){
                this.hashCode()
            } */else{
                throw StatusAndMessageError("not support method name:${method.name}")
            }
        }
    }
}